<?

/**
 *	request csv
 *	file establishes engine communication for csv parsing
 *
 *	parsing is based on a jsonstring, stored in moddump and connect by the settings (upload.csv)
 *	this jsonstring defines the types you can upload (user, project..) and the functions that are called after csv upload
 *	order is important as the functions are called in chronological order (after te process_content comes the process_fill..)
 *	every key value in the array of a type is a function
 *
 *	example
 *  {"user":{"content":{"email":"user","language":"lang"},"fill":{"rank":"1"},"unique":["user"]}}
 *	
 *	the json string above declares a csv parser for users (key is user)
 *	while parsing the csv the content is defined by  the function processor_content: column email will be the user column, language will enter the lang column. 
 *	all other data will be a part of the new object's meta
 *	after declaring the content the function processor_fill will be called (as it is the second key in the json string declared by the key 'user').
 *	this function fills up empty keys or adds keys in the new object array with a value declared as in the json string.
 * 	last function is the function processor_unique
 *	this function checks if the user already exists by the objects key 'user' (declared in the array).
 *	if the users exists an update will happen, otherwise an insert will happen.
 *
 *	@copyright	2010 - oneDot only<br>
 *  You can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; 
 *	either version 2 of the License, or (at your option) any later version.<br>
 *  The content is distributed in the hope that it will be useful, but without any warranty; 
 *	without even the implied warranty of merchantability or fitness for a particular purpose.  see the GNU General Public License for more details.
 *
 *	@package	Engine One
 *	@author		pieter van peteghem <pieter@onedotonly.be>
 *	@date		21 oct 2010
 */


class CTRLcsv extends CONTROL {

	


	/**
	 * constructor
	 * @param	object
	 */
	function __construct( $vars ) {
		global $DB;
	
		// constants
		if( $id = (int) engine_get( "csv.upload" ))
		
			$this->definition = json_decode( $DB->get_key( "json.object", $id, "json" ));

		
		$this->_addvars( $vars );

		if( $this->action != "list" )
			$this->create_object();
	}


	/**
	 * return parse options
	 * add type definition
	 */
	function filter_seed() {
		
		foreach( $this->definition as $k => $value )
			$buttons[] = strpos( $k, "." )?
				array( "title"=> "Process as " . translate( $k ) . " reference", "type"=> $k )
			:	array( "title"=> "Process as " . translate( $k ) . " list", "type"=> $k );

		return json_encode( $buttons );
	}
	
	
	/**
	 * check for set type and parse csv
	 */
	function filter_process() {
		global $Request;
		
		
		// Validate.
		if( $id		= (int) $Request->vars->id ) {
			
			$Csv	= new OBJECT( $Request->vars->objtype, $id );
			$file 	= $this->read_file( $id );
			$def	= $this->definition->{ $Request->vars->listtype };
		
		} else return null;
		

		// Process.
		if( count( $file->keys ) >= count( $def->content ))
		
			return ( substr( $Request->vars->listtype, 0, 3 ) == "ref" )?
				$this->process_ref( $file, $def )	
			:	$this->process( $file, $def );

	}
	
	/**
	 *	read file
	 *	open and process csv
	 *	@param		string		all of the json
	 *	@param		array		file info
	 */
	private function read_file( $id ) {
		
		$handle	= fopen( ROOT . ACCOUNT . "/www/DB/media/$id.csv", 'r' );
		
		while(( $raw = fgetcsv( $handle, 0, ';', '"' )) !== false ) {
				
				if( $rows ){ foreach( $raw as $n => $cell )
						$row[ $rows[0][ $n ]] = $cell;
				
						$rows[] = $row;
				} else  $rows[] = $raw;
				
				unset( $row );
		}
		
		return (object)
				array( "keys"=>  array_shift( $rows ), "rows"=> $rows );
	}
	
	private function process( $file, $def ) {
	

		if( $file->rows )
			foreach( $file->rows as $row ) {
				
				$row	= $this->procFuncfilter( $row, $def );
				$row	= $this->procArrayfilter( $row, $def );
				$row	= $this->procAlias( $row, $def );
				$row	= $this->procFill( $row, $def );
				
				$Object = $this->{( $def->unique )? "procUnique" : "procLazy" }( $row, $def );

				if( $this->funclist )
					foreach( $this->funclist as $func => $array ) $this->{ "procFunc_$func" }( $Object, $array );
			}
			
			return $this->ready( $file );
	}
	
	private function process_ref( $file, $def ) {
	

		if( $file->rows )
			foreach( $file->rows as $row ) {

				$row	= $this->procMetaRef( $row, $def );
				$row	= $this->procAlias( $row, $def );
				$row	= $this->procFill( $row, $def );
				
				$Object = new OBJECT( $row[ "parenttype" ], (int) $row[ "parentid" ]);
				
				if(( int ) $row[ "active" ])
					$Object->set_reference( $row[ "objtype" ], (int) $row[ "objectid" ], true );
				else
					$Object->delete_references();
				
				//$Object = $this->{( $def->unique )? "procUnique" : "procLazy" }( $row, $def );

				//if( $this->funclist )
				//	foreach( $this->funclist as $func => $array ) $this->{ "procFunc_$func" }( $Object, $array );
			
			}
			
			return $this->ready( $file );
	}
	
		private function procArrayfilter( $row, $def ) {
				
			foreach( $def->content as $key => $split )
				if( strpos( $split, "." ) && ( $split = explode( ".", $split )) && array_key_exists( $key , $row )){
					
					$row[ $split[ 0 ]][ $split[ 1 ]] = $row[ $key ];
					unset( $row[ $key ]);
				}
			
			return $row;
		}
		
		private function procFuncfilter( $row, $def ) {
				
			foreach( $def->content as $key => $split )
				if( strpos( $split, ":" ) && ( $split = explode( ":", $split )) && array_key_exists( $key , $row )){
					
					$this->funclist[ $func = array_shift( $split )][ array_shift( $split ) . (( $func == "text" )? ".$key": "" )] = ( object ) array( "param"=> $split, "cell"=> $row[ $key ]);
					unset( $row[ $key ]);
				}
				
			return $row;
		}
		
		private function procAlias( $row, $def ) {
		
			foreach( $row as $key => $cell )
				if(( $newkey = $def->content->{ $key })){
				
					 $row[ $newkey ] = $cell;
					 unset( $row[ $key ]);
				}

			return $row;
		}
	
		private function procFill( $row, $def ) {
		
			return 	( $def->fill )?
					  (array) object_merge( $def->fill, $row )
					: $row;
		}
		
		private function procMetaRef( $row, $def ) {
			global $DB;
			
			foreach( $def->content as $key => $condt )
				if( $row[ $key ] && count( $condt = explode( ":", $condt )) > 1) {

					$row[  $condt[3]] = (int) $DB->get_key( $condt[2], "meta regexp '\"{$condt[1]}\":\"{$row[ $key ]}\"'" );
					unset( $row[ $key ]);
				}
			
			return $row;
		}
		
		private function procUnique( $row, $def ) {
			global $DB, $Request;
			
			foreach( $def->unique as $unq )
				$query[] = ( strpos( $unq, ":" ))?
							 $this->{ "procUnique_" . array_shift( $unq = explode( ":", $unq ))}( $row, $unq ) 
						:	 "`$unq`='" . $row[ $unq ] . "'";

			
			if( count( array_filter( $query )) == count( $def->unique ) &&
			  ( $id = (int) $DB->get_key( $Request->vars->listtype, implode( " && ", array_filter( $query ))))) {

				$Object = new OBJECT( $Request->vars->listtype, $id );
				$this->report[] = "update: ID $id";

				foreach( $row as $key => $cell )
					$Object->set( $key, $cell, is_array( $cell ));

			} else	$Object = $this->procLazy( $row, $def );
			
			return $Object;
		}
	
		private function procLazy( $row, $def ) {
			global $Request;

			return new OBJECT( $Request->vars->listtype, 0, true, $row );
		}
		
		
		private function procUnique_text( $row, $unq ) {
			global $Engine;
			
			$string = ( $row[ $unq[ 1 ]])? $row[ $unq[ 1 ]] : $this->funclist[ "text" ][ $unq[ 2 ]]->cell;

			if( $search = $Engine->text->search( $string, ( $unq[ 3 ])? "long": "short" )) {
				foreach( $search as $row ) $ids[] = $row[ "textid" ];
				
				if( array_filter( $ids ))
					return $unq[ 2 ] . " in(" . implode( ",", array_filter( $ids )) . ")";
			}
		}
		
		private function procUnique_meta( $row, $unq ) {
			global $Engine;

			return "meta regexp '\"{$unq[ 1 ]}\":.{$row[ $unq[ 1 ]]}.'";
		}
		
		private function procUnique_ref( $row, $unq ) {
			global $DB, $Request;
			
			if(( $id = $row[ $unq[ 1 ]]) || ( $id = $this->funclist[ "ref" ][ $unq[ 2 ]]->cell )){
			
				$ids_m = $DB->reference( $Request->vars->listtype, null, $unq[ 2 ], (int) $id );
				$ids_s = $DB->reference( $unq[ 2 ], (int) $id, $Request->vars->listtype, null );
				$ids = ( $ids_m && $ids_s )? array_merge( $ids_m, $ids_s ) : (( $ids_m )? $ids_m : $ids_s );
			}
			
			if( $ids && array_filter( $ids ))
				return "ID in(" . implode( ",", array_filter( $ids )) . ")";
			
		}
		
		
		private function procFunc_text( $Object, $list ) {
			global $Engine;
			
			foreach( $list as $key => $val )
				if( $val->cell ) {
				
					$key = array_shift( explode( ".", $key ));
				
				print_r( $val->param );
					$value = (int) $Engine->text->set( $val->cell, (int) $Object->get( $key ), ( $val->param[ 0 ])? $val->param[ 0 ]:"short", ( $val->param[ 1 ])? $val->param[ 1 ]: LANG );
				
					if( strpos( $key, "." ) && ( $key = explode( ".", $key ))) {
						$json = $Object->get( $key[ 0 ]);
						$json->{ $key[ 1 ]} = $value;
					}
					
					$Object->set( is_array( $key )? $key[ 0 ]: $key, is_array( $key )? (array) $json: $value, is_array( $key ) );
					
				}
		}
		
		private function procFunc_ref( $Object, $list ) {

			foreach( $list as $key => $val )
				 if( $val->cell )
				 
				 	 foreach( explode( ",", $val->cell ) as $id ) 
				 		$Object->set_reference( $key, (int) $id, $val->param[ 0 ]);
		}
		
		
		private function procFunc_latlng( $Object, $list ) {

			foreach( $list as $key => $val )
				if( $val->cell ) {
				 
#				Google maps interaction
				$address = strtolower( $Object->get( "adres" ) . "+" . $Object->get( "pcode" ) . "+" . $Object->get( "country" )); 
				$location	= json_decode( file_get_contents('http://maps.google.com/maps/geo?q=' . urlencode( $address ) . '&key=' . engine_get( 'mod.google.api.code' ) . '&oe=utf8' ));
				
				// check address
				if ( $location->Status->code == 200 ) {
		
					// get ll and save to db
					$latLng = $location->Placemark[0]->Point->coordinates;
					$Object->values[ 'meta' ]->ll = $latLng[1] . ',' . $latLng[0];
					$Object->set( "meta", $Object->values[ 'meta' ], true );
			
						$this->report[] = "Address noted";
				} else	$this->report[] = "Address not found, sorry.";
			
				
			}		 	
		}


	function ready( $file ) {
		
		if( !$this->report ) $this->report = array(); 
		
		array_unshift( $this->report, "..." );
		array_unshift( $this->report, count( $file->rows ) . " entries completed (" . count( $this->report ) . " updates)" );
		array_unshift( $this->report, "<strong>process reday</strong>" );
		
		return json_encode( $this->report );
	}

}
